package com.hmy.finance.service.core.dto;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmy.crm.api.bo.response.OpportunityFeignInfoResponse;
import com.hmy.finance.api.bo.core.request.StartRentalRequest;
import com.hmy.finance.api.bo.core.request.enums.FeeTypeEnum;
import com.hmy.finance.api.bo.core.response.StartRentalResponse;
import com.hmy.finance.common.enums.BusinessBillTypeEnum;
import com.hmy.finance.common.enums.ProfitLossStatusEnum;
import com.hmy.finance.dal.po.DeviceProfitLossDetailPo;
import com.hmy.finance.dal.po.DeviceRentalRecordPo;
import com.hmy.finance.dal.po.ProfitLossRecordPo;
import com.hmy.finance.dal.po.json.*;
import com.hmy.finance.service.core.dto.vos.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 进场起租业务逻辑处理流程参数
 *
 * @author songkf
 */
@Data
@Slf4j
public class StartRentalDto implements Serializable {
    private static final long serialVersionUID = -2712231209548564384L;
    /**
     * 销售合同信息
     */
    private ContractInfoVo contractInfo;
    /**
     * 客户信息
     */
    private CustomerInfoVo customerInfo;
    /**
     * 入场单信息
     */
    private EntryFormInfoVo entryFormInfo;
    /**
     * 订单信息
     */
    private OrderInfoVo orderInfo;
    /**
     * 商机信息
     */
    private OpportunityFeignInfoResponse opportunityFeignInfoResponse;
    /**
     * 设备租赁记录
     */
    private List<DeviceRentalRecordPo> deviceRentalRecordPoList = new ArrayList<>();
    /**
     * 损益业务记录
     */
    private List<ProfitLossRecordPo> profitLossRecordPoList = new ArrayList<>();
    /**
     * 设备损益明细记录
     */
    private List<DeviceProfitLossDetailPo> deviceProfitLossDetailPoList = new ArrayList<>();

    /**
     * 总月租价格
     */
    private BigDecimal totalRentalPrice;
    /**
     * 已计算的运费
     */
    private BigDecimal dividedShippingFee = BigDecimal.ZERO;

    private BigDecimal dividedModificationFee = BigDecimal.ZERO;

    /**
     * 构建进场起租业务逻辑处理流程参数
     *
     * @param request 请求参数
     * @return 进场起租业务逻辑处理流程参数
     * @author songkf
     */
    public static StartRentalDto buildStartRentalDto(StartRentalRequest request) {
        StartRentalDto startRentalDto = new StartRentalDto();
        startRentalDto.setContractInfo(BeanUtil.copyProperties(request.getContractInfo(), ContractInfoVo.class));
        startRentalDto.setCustomerInfo(BeanUtil.copyProperties(request.getCustomerInfo(), CustomerInfoVo.class));
        startRentalDto.setEntryFormInfo(BeanUtil.copyProperties(request.getEntryFormInfo(), EntryFormInfoVo.class));
        startRentalDto.setOrderInfo(BeanUtil.copyProperties(request.getOrderInfo(), OrderInfoVo.class));
        return startRentalDto;
    }

    /**
     * 组装设备租赁记录
     *
     * @author songkf
     */
    public void assembleRentalRecord(DefaultIdentifierGenerator identifierGenerator) {
        totalRentalPrice = this.entryFormInfo.getDeviceInfoList().stream().map(DeviceInfoVo::getMonthlyRentalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        //遍历entryFormInfo的deviceList，将每个设备的信息组装成DeviceRentalRecordPo对象，放入deviceRentalRecordPoList中
//        deviceRentalRecordPoList = this.entryFormInfo.getDeviceInfoList().stream().map(deviceInfoVo -> accept(deviceInfoVo, identifierGenerator)).collect(Collectors.toList());
        for (int i = 0; i < this.entryFormInfo.getDeviceInfoList().size(); i++) {
            DeviceInfoVo deviceInfoVo = this.entryFormInfo.getDeviceInfoList().get(i);
            deviceRentalRecordPoList.add(accept(deviceInfoVo, identifierGenerator, i));
        }
    }


    /**
     * 将设备信息组装成DeviceRentalRecordPo对象
     *
     * @param deviceInfoVo 设备信息
     * @param i
     * @author songkf
     */
    private DeviceRentalRecordPo accept(DeviceInfoVo deviceInfoVo, DefaultIdentifierGenerator identifierGenerator, int i) {
        DeviceRentalRecordPo deviceRentalRecordPo = new DeviceRentalRecordPo();
        //填充客户信息，通过customerInfo构建CustomerExtensionInfoJson对象
        deviceRentalRecordPo.setCustomerId(this.customerInfo.getCustomerId());
        deviceRentalRecordPo.setCustomerExtensionInfo(getCustomerExtensionInfoJson());
        //填充合同信息，通过contractInfo构建ContractExtensionInfoJson对象
        deviceRentalRecordPo.setContractId(this.contractInfo.getContractId());
        deviceRentalRecordPo.setContractNo(this.contractInfo.getContractNo());
        deviceRentalRecordPo.setContractExtensionInfo(getContractExtensionInfoJson());
        //填充订单信息，通过orderInfo构建OrderExtensionInfoJson对象
        deviceRentalRecordPo.setOrderId(this.orderInfo.getOrderId());
        OrderExtensionInfoJson orderExtensionInfo = getOrderExtensionInfoJson();
        deviceRentalRecordPo.setOrderExtensionInfo(orderExtensionInfo);
        //将deviceInfoVo的属性构建成DeviceInfoJson对象
        deviceRentalRecordPo.setDeviceId(deviceInfoVo.getDeviceId());
        deviceRentalRecordPo.setDeviceNo(deviceInfoVo.getDeviceNo());
        deviceRentalRecordPo.setDeviceExtensionInfo(getDeviceInfoJson(deviceInfoVo));
        //填充设备租赁记录的其他属性
        deviceRentalRecordPo.setEntryFormId(this.entryFormInfo.getEntryFormId());
        deviceRentalRecordPo.setDailyRentalPrice(deviceInfoVo.getDailyRentalPrice());
        deviceRentalRecordPo.setMonthlyRentalPrice(deviceInfoVo.getMonthlyRentalPrice());
        deviceRentalRecordPo.setRentalStartTime(this.entryFormInfo.getRentalStartTime());
        deviceRentalRecordPo.setSaleManagerDeptId(this.orderInfo.getSaleManagerDeptId());
        deviceRentalRecordPo.setSaleManagerId(this.orderInfo.getSaleManagerId());
        deviceRentalRecordPo.setSaleManagerName(this.orderInfo.getSaleManagerName());
        //设置为前一天的23:59:59，方便对账使用
        deviceRentalRecordPo.setLastReconciliationTime(entryFormInfo.getRentalStartTime());
        deviceRentalRecordPo.setId(identifierGenerator.nextId(deviceRentalRecordPo));
        deviceRentalRecordPo.setEntryShippingInfo(acceptShippingInfo(deviceInfoVo.getMonthlyRentalPrice(), i));
        deviceRentalRecordPo.setModificationFeeInfo(acceptModificationInfo(i));
        //后增加的字段信息
        deviceRentalRecordPo.setExpenseCycleStartTime(deviceRentalRecordPo.getRentalStartTime());
        deviceRentalRecordPo.setExpenseCycleEndTime(null);
        log.info("deviceRentalRecordPo={}", deviceRentalRecordPo);
        return deviceRentalRecordPo;
    }

    /**
     * 通过entryFormInfo构建ModificationFeeInfoJson对象
     *
     * @return ModificationFeeInfoJson对象
     * @author songkf
     */
    private ModificationFeeInfoJson acceptModificationInfo(int i) {
        ModificationFeeInfoJson modificationFeeInfoJson = new ModificationFeeInfoJson();
        modificationFeeInfoJson.setModificationAllAmount(this.entryFormInfo.getModificationAmount());
        if (this.entryFormInfo.getModificationAmount() != null && this.entryFormInfo.getDeviceInfoList() != null && !this.entryFormInfo.getDeviceInfoList().isEmpty()) {
            modificationFeeInfoJson.setModificationTotalAmount(this.entryFormInfo.getModificationAmount().divide(BigDecimal.valueOf(this.entryFormInfo.getDeviceInfoList().size()), 5, RoundingMode.HALF_UP));
        } else {
            modificationFeeInfoJson.setModificationTotalAmount(BigDecimal.ZERO);
        }
        if (this.entryFormInfo.getModificationWaiverRuleList() != null && !this.entryFormInfo.getModificationWaiverRuleList().isEmpty()) {
            modificationFeeInfoJson.setModificationWaiverRuleList(this.entryFormInfo.getModificationWaiverRuleList().stream().map(waiverRuleVo -> {
                WaiverRuleJson waiverRuleJson = new WaiverRuleJson();
                waiverRuleJson.setWaiverDays(waiverRuleVo.getWaiverDays());
                waiverRuleJson.setWaiverRate(waiverRuleVo.getWaiverRate());
                return waiverRuleJson;
            }).collect(Collectors.toList()));
        }
        return modificationFeeInfoJson;
    }

    /**
     * 通过entryFormInfo构建ShippingInfoJson对象
     *
     * @return ShippingInfoJson对象
     * @author songkf
     */
    private ShippingInfoJson acceptShippingInfo(BigDecimal monthlyRentalPrice, int i) {
        ShippingInfoJson shippingInfoJson = new ShippingInfoJson();
        shippingInfoJson.setShippingAllAmount(this.entryFormInfo.getEntryShippingInfo().getShippingTotalAmount());
        if (i == this.entryFormInfo.getDeviceInfoList().size() - 1) {
            shippingInfoJson.setShippingTotalAmount(this.entryFormInfo.getEntryShippingInfo().getShippingTotalAmount().subtract(dividedShippingFee, new MathContext(5, RoundingMode.HALF_UP)));
        } else {
            BigDecimal dividedFee = this.entryFormInfo.getEntryShippingInfo().getShippingTotalAmount().multiply(monthlyRentalPrice).divide(totalRentalPrice, 5, RoundingMode.HALF_UP);
            shippingInfoJson.setShippingTotalAmount(dividedFee);
            dividedShippingFee = dividedShippingFee.add(dividedFee);
        }
        shippingInfoJson.setShippingWaiverRuleList(this.entryFormInfo.getEntryShippingInfo().getShippingWaiverRuleList().stream().map(waiverRuleVo -> {
            WaiverRuleJson waiverRuleJson = new WaiverRuleJson();
            waiverRuleJson.setWaiverDays(waiverRuleVo.getWaiverDays());
            waiverRuleJson.setWaiverRate(waiverRuleVo.getWaiverRate());
            return waiverRuleJson;
        }).collect(Collectors.toList()));
        return shippingInfoJson;
    }

    /**
     * 通过deviceInfoVo构建DeviceInfoJson对象
     *
     * @param deviceInfoVo 设备信息
     * @return DeviceInfoJson对象
     * @author songkf
     */
    private DeviceInfoJson getDeviceInfoJson(DeviceInfoVo deviceInfoVo) {
        DeviceInfoJson deviceExtensionInfo = new DeviceInfoJson();
        deviceExtensionInfo.setDeviceId(deviceInfoVo.getDeviceId());
        deviceExtensionInfo.setDeviceNo(deviceInfoVo.getDeviceNo());
        deviceExtensionInfo.setDeviceHeight(deviceInfoVo.getDeviceHeight());
        deviceExtensionInfo.setDeviceModel(deviceInfoVo.getDeviceModel());
        deviceExtensionInfo.setDeviceType(deviceInfoVo.getDeviceType());
        return deviceExtensionInfo;
    }

    /**
     * 通过orderInfo构建OrderExtensionInfoJson对象
     *
     * @return
     * @author songkf
     */
    private OrderExtensionInfoJson getOrderExtensionInfoJson() {
        OrderExtensionInfoJson orderExtensionInfo = new OrderExtensionInfoJson();
        orderExtensionInfo.setOrderId(this.orderInfo.getOrderId());
        orderExtensionInfo.setOrderNo(this.orderInfo.getOrderNo());
        orderExtensionInfo.setAccountPeriod(this.orderInfo.getAccountPeriod());
        orderExtensionInfo.setAccountPeriodDays(this.orderInfo.getAccountPeriodDays());
        orderExtensionInfo.setSettlementMethod(this.orderInfo.getSettlementMethod());
        orderExtensionInfo.setSaleManagerDeptId(this.orderInfo.getSaleManagerDeptId());
        orderExtensionInfo.setSaleManagerId(this.orderInfo.getSaleManagerId());
        orderExtensionInfo.setSaleManagerName(this.orderInfo.getSaleManagerName());
        orderExtensionInfo.setProjectId(this.orderInfo.getProjectId());
        orderExtensionInfo.setProjectName(this.orderInfo.getProjectName());
        if (this.opportunityFeignInfoResponse == null) {
            orderExtensionInfo.setProjectNo(this.orderInfo.getProjectNo());
        } else {
            orderExtensionInfo.setProjectNo(this.opportunityFeignInfoResponse.getProjectNo());
        }
        return orderExtensionInfo;
    }

    /**
     * 通过contractInfo构建ContractExtensionInfoJson对象
     *
     * @return
     * @author songkf
     */
    private ContractExtensionInfoJson getContractExtensionInfoJson() {
        ContractExtensionInfoJson contractExtensionInfo = new ContractExtensionInfoJson();
        contractExtensionInfo.setContractId(this.contractInfo.getContractId());
        contractExtensionInfo.setContractNo(this.contractInfo.getContractNo());
        contractExtensionInfo.setContractName(this.contractInfo.getContractName());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");

        if (this.contractInfo.getContractSignTime() != null) {
            // 创建 DateTimeFormatter 对象，指定日期时间格式
            contractExtensionInfo.setContractSignTime(this.contractInfo.getContractSignTime().format(formatter));
        } else {
            contractExtensionInfo.setContractSignTime(LocalDateTime.now().format(formatter));
        }
        return contractExtensionInfo;
    }

    /**
     * 通过customerInfo构建CustomerExtensionInfoJson对象
     *
     * @return
     * @author songkf
     */
    private CustomerExtensionInfoJson getCustomerExtensionInfoJson() {
        CustomerExtensionInfoJson customerExtensionInfo = new CustomerExtensionInfoJson();
        customerExtensionInfo.setCustomerId(this.customerInfo.getCustomerId());
        customerExtensionInfo.setCustomerName(this.customerInfo.getCustomerName());
        if (this.opportunityFeignInfoResponse == null) {
            customerExtensionInfo.setCustomerNo(this.customerInfo.getCustomerNo());
            customerExtensionInfo.setSignatoryId(this.customerInfo.getSignatoryId());
            customerExtensionInfo.setCustomerType(this.customerInfo.getCustomerType());
            customerExtensionInfo.setSignatoryIdCardNumber(this.customerInfo.getSignatoryIdCardNumber());
        } else {
            customerExtensionInfo.setCustomerNo(this.opportunityFeignInfoResponse.getCustomerNo());
            customerExtensionInfo.setSignatoryId(this.opportunityFeignInfoResponse.getCustomerContactorId());
            customerExtensionInfo.setCustomerType(Math.toIntExact(this.opportunityFeignInfoResponse.getCustomerType()));
        }
        customerExtensionInfo.setSignatoryName(this.customerInfo.getSignatoryName());
        customerExtensionInfo.setSignatoryPhone(this.customerInfo.getSignatoryPhone());
        return customerExtensionInfo;
    }

    /**
     * 获取进场起租业务逻辑处理流程返回结果
     *
     * @return 进场起租业务逻辑处理流程返回结果
     * @author songkf
     */
    public StartRentalResponse getResponse() {
        return new StartRentalResponse(Boolean.TRUE);
    }

    /**
     * 组装进场运费和进场运费减免损益业务记录
     *
     * @param identifierGenerator id生成器
     * @author songkf
     */
    public void assembleShippingFeeProfitLossRecord(DefaultIdentifierGenerator identifierGenerator) {
        //基于entryFormInfo的entryShippingInfo，构建ProfitLossRecordPo对象，放入profitLossRecordPoList中
        //构建进场运费损益业务记录
        ProfitLossRecordPo entryShippingProfitLossRecord = new ProfitLossRecordPo();
        entryShippingProfitLossRecord.setCustomerId(this.customerInfo.getCustomerId());
        entryShippingProfitLossRecord.setContractId(this.contractInfo.getContractId());
        entryShippingProfitLossRecord.setBusinessBillId(this.getEntryFormInfo().getEntryFormId());
        entryShippingProfitLossRecord.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
        entryShippingProfitLossRecord.setFeeType(FeeTypeEnum.SHIPPING_FEE);
        entryShippingProfitLossRecord.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
        entryShippingProfitLossRecord.setTotalFeeAmount(this.entryFormInfo.getEntryShippingInfo().getShippingTotalAmount());
        entryShippingProfitLossRecord.setFeeIncurredTime(this.entryFormInfo.getRentalStartTime());
        entryShippingProfitLossRecord.setId(identifierGenerator.nextId(entryShippingProfitLossRecord));
        this.profitLossRecordPoList.add(entryShippingProfitLossRecord);
        //将进场运费分摊到deviceRentalRecordPoList的每个设备上，构建设备损益明细记录(DeviceProfitLossDetailPo)，放入deviceProfitLossDetailPoList中.最后一条数据的fee为总费用减去前面所有设备的fee之和
        assembleDeviceProfitLossDetail(identifierGenerator, this.entryFormInfo.getRentalStartTime(), entryShippingProfitLossRecord.getId(), entryShippingProfitLossRecord.getTotalFeeAmount(), FeeTypeEnum.SHIPPING_FEE);

        //遍历entryFormInfo的EntryShippingInfo的shippingWaiverRuleList，构建进场运费减免损益记录
//        this.entryFormInfo.getEntryShippingInfo().getShippingWaiverRuleList().forEach(shippingWaiverRule -> {
//            ProfitLossRecordPo entryShippingWaiverProfitLossRecord = new ProfitLossRecordPo();
//            entryShippingWaiverProfitLossRecord.setCustomerId(this.customerInfo.getCustomerId());
//            entryShippingWaiverProfitLossRecord.setContractId(this.contractInfo.getContractId());
//            entryShippingWaiverProfitLossRecord.setBusinessBillId(this.getEntryFormInfo().getEntryFormId());
//            entryShippingWaiverProfitLossRecord.setFeeType(FeeTypeEnum.SHIPPING_FEE_WAIVER);
//            entryShippingWaiverProfitLossRecord.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
//            entryShippingWaiverProfitLossRecord.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
//            entryShippingWaiverProfitLossRecord.setTotalFeeAmount(this.entryFormInfo.getEntryShippingInfo().getShippingTotalAmount().multiply(BigDecimal.valueOf(shippingWaiverRule.getWaiverRate())));
//            //当前时间往后延shippingWaiverRule.getModificationWaiverDays()天
//            entryShippingWaiverProfitLossRecord.setFeeIncurredTime(this.entryFormInfo.getRentalStartTime().plusDays(shippingWaiverRule.getWaiverDays()).minusDays(1));
//            entryShippingWaiverProfitLossRecord.setId(identifierGenerator.nextId(entryShippingWaiverProfitLossRecord));
//            assembleShippingWaiverDeviceProfitLossDetail(identifierGenerator, entryShippingWaiverProfitLossRecord);
//            this.profitLossRecordPoList.add(entryShippingWaiverProfitLossRecord);
//        });
    }

    /**
     * 组装进场运费减免
     *
     * @param identifierGenerator
     * @param entryShippingWaiverProfitLossRecord
     * @author songkf
     */
    private void assembleShippingWaiverDeviceProfitLossDetail(DefaultIdentifierGenerator identifierGenerator, ProfitLossRecordPo entryShippingWaiverProfitLossRecord) {
        List<DeviceProfitLossDetailPo> deviceProfitLossDetailPoList_self = new ArrayList<>();

        BigDecimal totalMonthlyRentalPrice = deviceRentalRecordPoList.stream().map(DeviceRentalRecordPo::getMonthlyRentalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        //遍历deviceRentalRecordPoList，构建进场运费减免损益明细
        for (int i = 0; i < deviceRentalRecordPoList.size(); i++) {
            DeviceRentalRecordPo deviceRentalRecord = deviceRentalRecordPoList.get(i);
            DeviceProfitLossDetailPo deviceProfitLossDetail = new DeviceProfitLossDetailPo();
            deviceProfitLossDetail.setProfitLossRecordId(entryShippingWaiverProfitLossRecord.getId());
            deviceProfitLossDetail.setDeviceId(deviceRentalRecord.getDeviceId());
            deviceProfitLossDetail.setDeviceNo(deviceRentalRecord.getDeviceExtensionInfo().getDeviceNo());
            deviceProfitLossDetail.setDeviceRentalRecordId(deviceRentalRecord.getId());
            deviceProfitLossDetail.setContractNo(deviceRentalRecord.getContractNo());
            deviceProfitLossDetail.setContractId(this.contractInfo.getContractId());
            deviceProfitLossDetail.setFeeType(FeeTypeEnum.SHIPPING_FEE_WAIVER);
            deviceProfitLossDetail.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
            if (i == deviceRentalRecordPoList.size() - 1) {
                deviceProfitLossDetail.setFee(entryShippingWaiverProfitLossRecord.getTotalFeeAmount().subtract(deviceProfitLossDetailPoList_self.stream().map(DeviceProfitLossDetailPo::getFee).reduce(BigDecimal.ZERO, BigDecimal::add)));
            } else {
                deviceProfitLossDetail.setFee(entryShippingWaiverProfitLossRecord.getTotalFeeAmount().multiply(deviceRentalRecord.getMonthlyRentalPrice()).divide(totalMonthlyRentalPrice, 5, RoundingMode.HALF_UP));
            }
            deviceProfitLossDetail.setFeeIncurredTime(entryShippingWaiverProfitLossRecord.getFeeIncurredTime());
            deviceProfitLossDetail.setId(identifierGenerator.nextId(deviceProfitLossDetail));
            deviceProfitLossDetailPoList_self.add(deviceProfitLossDetail);
        }
        deviceProfitLossDetailPoList.addAll(deviceProfitLossDetailPoList_self);
    }

    /**
     * 组装设备改装费损益业务记录
     *
     * @param identifierGenerator id生成器
     * @author songkf
     */
    public void assembleDeviceModificationFeeProfitLossRecord(DefaultIdentifierGenerator identifierGenerator) {
        if (this.entryFormInfo.getModificationAmount() != null && this.entryFormInfo.getModificationAmount().compareTo(BigDecimal.ZERO) > 0) {
            //构建设备改装费损益业务记录
            ProfitLossRecordPo deviceModificationFeeProfitLossRecord = new ProfitLossRecordPo();
            deviceModificationFeeProfitLossRecord.setCustomerId(this.customerInfo.getCustomerId());
            deviceModificationFeeProfitLossRecord.setContractId(this.contractInfo.getContractId());
            deviceModificationFeeProfitLossRecord.setBusinessBillId(this.getEntryFormInfo().getEntryFormId());
            deviceModificationFeeProfitLossRecord.setFeeType(FeeTypeEnum.MODIFICATION_FEE);
            deviceModificationFeeProfitLossRecord.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
            deviceModificationFeeProfitLossRecord.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
            deviceModificationFeeProfitLossRecord.setTotalFeeAmount(this.entryFormInfo.getModificationAmount());
            deviceModificationFeeProfitLossRecord.setFeeIncurredTime(this.entryFormInfo.getRentalStartTime());
            deviceModificationFeeProfitLossRecord.setId(identifierGenerator.nextId(deviceModificationFeeProfitLossRecord));
            this.profitLossRecordPoList.add(deviceModificationFeeProfitLossRecord);
            //将设备改装费分摊到deviceRentalRecordPoList的每个设备上，构建设备损益明细记录(DeviceProfitLossDetailPo)，放入deviceProfitLossDetailPoList中.最后一条数据的fee为总费用减去前面所有设备的fee之和
            BigDecimal totalAmount = this.entryFormInfo.getModificationAmount();
            if (totalAmount != null && totalAmount.compareTo(BigDecimal.ZERO) > 0) {
                assembleDeviceProfitLossDetail(identifierGenerator, deviceModificationFeeProfitLossRecord.getFeeIncurredTime(), deviceModificationFeeProfitLossRecord.getId(), totalAmount, FeeTypeEnum.MODIFICATION_FEE);
            }

            //遍历entryFormInfo的modificationWaiverRuleList，构建设备改装费减免损益记录
            /*this.entryFormInfo.getModificationWaiverRuleList().forEach(modificationWaiverRule -> {
                ProfitLossRecordPo deviceModificationWaiverFeeProfitLossRecord = new ProfitLossRecordPo();
                deviceModificationWaiverFeeProfitLossRecord.setCustomerId(this.customerInfo.getCustomerId());
                deviceModificationWaiverFeeProfitLossRecord.setContractId(this.contractInfo.getContractId());
                deviceModificationWaiverFeeProfitLossRecord.setBusinessBillId(this.getEntryFormInfo().getEntryFormId());
                deviceModificationWaiverFeeProfitLossRecord.setFeeType(FeeTypeEnum.MODIFICATION_FEE_WAIVER);
                deviceModificationWaiverFeeProfitLossRecord.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
                deviceModificationWaiverFeeProfitLossRecord.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
                deviceModificationWaiverFeeProfitLossRecord.setTotalFeeAmount(this.entryFormInfo.getModificationAmount().multiply(BigDecimal.valueOf(modificationWaiverRule.getWaiverRate())));
                //当前时间往后延modificationWaiverRule.getModificationWaiverDays()天
                deviceModificationWaiverFeeProfitLossRecord.setFeeIncurredTime(this.entryFormInfo.getRentalStartTime().plusDays(modificationWaiverRule.getWaiverDays()));
                deviceModificationWaiverFeeProfitLossRecord.setId(identifierGenerator.nextId(deviceModificationWaiverFeeProfitLossRecord));
                assembleModificationFeeWaiverDeviceProfitLossDetail(identifierGenerator, deviceModificationWaiverFeeProfitLossRecord.getId(), deviceModificationWaiverFeeProfitLossRecord.getFeeIncurredTime(), deviceModificationWaiverFeeProfitLossRecord.getTotalFeeAmount(), FeeTypeEnum.MODIFICATION_FEE_WAIVER);
                this.profitLossRecordPoList.add(deviceModificationWaiverFeeProfitLossRecord);
            });*/
        }
    }

    private void assembleModificationFeeWaiverDeviceProfitLossDetail(DefaultIdentifierGenerator identifierGenerator, Long id, LocalDateTime feeIncurredTime, BigDecimal totalFeeAmount, FeeTypeEnum feeTypeEnum) {
        List<DeviceProfitLossDetailPo> deviceProfitLossDetailPoList_self = new ArrayList<>();
        for (int i = 0; i < deviceRentalRecordPoList.size(); i++) {
            DeviceProfitLossDetailPo deviceProfitLossDetailPo = new DeviceProfitLossDetailPo();
            DeviceRentalRecordPo deviceRentalRecordPo = deviceRentalRecordPoList.get(i);
            deviceProfitLossDetailPo.setDeviceRentalRecordId(deviceRentalRecordPo.getId());
            deviceProfitLossDetailPo.setContractNo(deviceRentalRecordPo.getContractNo());
            deviceProfitLossDetailPo.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
            deviceProfitLossDetailPo.setProfitLossRecordId(id);
            deviceProfitLossDetailPo.setDeviceId(deviceRentalRecordPo.getDeviceId());
            deviceProfitLossDetailPo.setDeviceNo(deviceRentalRecordPo.getDeviceExtensionInfo().getDeviceNo());
            deviceProfitLossDetailPo.setContractId(this.contractInfo.getContractId());
            deviceProfitLossDetailPo.setFeeType(feeTypeEnum);
            deviceProfitLossDetailPo.setFeeIncurredTime(feeIncurredTime);
            if (i == deviceRentalRecordPoList.size() - 1) {
                deviceProfitLossDetailPo.setFee(totalFeeAmount.subtract(deviceProfitLossDetailPoList_self.stream().map(DeviceProfitLossDetailPo::getFee).reduce(BigDecimal.ZERO, BigDecimal::add)));
            } else {
                deviceProfitLossDetailPo.setFee(totalFeeAmount.divide(BigDecimal.valueOf(deviceRentalRecordPoList.size()), 5, RoundingMode.HALF_UP));
            }
            deviceProfitLossDetailPo.setId(identifierGenerator.nextId(deviceProfitLossDetailPo));
            deviceProfitLossDetailPoList_self.add(deviceProfitLossDetailPo);
        }
        deviceProfitLossDetailPoList.addAll(deviceProfitLossDetailPoList_self);
    }

    /**
     * 组装设备损益明细记录
     *
     * @param identifierGenerator id生成器
     * @param profitLossRecordId  损益业务记录ID
     * @param totalAmount         总费用
     * @param businessBillType    业务单据类型
     * @author songkf
     */
    private void assembleDeviceProfitLossDetail(DefaultIdentifierGenerator identifierGenerator, LocalDateTime feeIncurredTime, Long profitLossRecordId, BigDecimal totalAmount, FeeTypeEnum businessBillType) {
        List<DeviceProfitLossDetailPo> deviceProfitLossDetailPoList_self = new ArrayList<>();
        //累计计算每个设备的月租金
        BigDecimal totalMonthlyRentalPrice = deviceRentalRecordPoList.stream().map(DeviceRentalRecordPo::getMonthlyRentalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        for (int i = 0; i < deviceRentalRecordPoList.size(); i++) {
            DeviceProfitLossDetailPo deviceProfitLossDetailPo = new DeviceProfitLossDetailPo();
            DeviceRentalRecordPo deviceRentalRecordPo = deviceRentalRecordPoList.get(i);
            deviceProfitLossDetailPo.setDeviceRentalRecordId(deviceRentalRecordPo.getId());
            deviceProfitLossDetailPo.setContractNo(deviceRentalRecordPo.getContractNo());
            deviceProfitLossDetailPo.setBusinessBillType(BusinessBillTypeEnum.ENTRY);
            deviceProfitLossDetailPo.setProfitLossRecordId(profitLossRecordId);
            deviceProfitLossDetailPo.setDeviceId(deviceRentalRecordPo.getDeviceId());
            deviceProfitLossDetailPo.setDeviceNo(deviceRentalRecordPo.getDeviceExtensionInfo().getDeviceNo());
            deviceProfitLossDetailPo.setContractId(this.contractInfo.getContractId());
            deviceProfitLossDetailPo.setFeeType(businessBillType);
            deviceProfitLossDetailPo.setFeeIncurredTime(feeIncurredTime);
            if (i == deviceRentalRecordPoList.size() - 1) {
                BigDecimal dividedFee = totalAmount.subtract(deviceProfitLossDetailPoList_self.stream().map(DeviceProfitLossDetailPo::getFee).reduce(BigDecimal.ZERO, BigDecimal::add));
                deviceProfitLossDetailPo.setFee(dividedFee);
                if (!businessBillType.equals(FeeTypeEnum.MODIFICATION_FEE) && !businessBillType.equals(FeeTypeEnum.MODIFICATION_FEE_WAIVER)) {
                    ShippingInfoJson exitShippingInfo = deviceRentalRecordPo.getEntryShippingInfo();
                    if (exitShippingInfo != null) {
                        exitShippingInfo.setShippingTotalAmount(dividedFee);
                        deviceRentalRecordPo.setEntryShippingInfo(exitShippingInfo);
                    }
                }
            } else {
                if (businessBillType.equals(FeeTypeEnum.MODIFICATION_FEE) || businessBillType.equals(FeeTypeEnum.MODIFICATION_FEE_WAIVER)) {
                    deviceProfitLossDetailPo.setFee(totalAmount.divide(BigDecimal.valueOf(deviceRentalRecordPoList.size()), 5, RoundingMode.HALF_UP));
                } else {
                    BigDecimal divideFee = totalAmount.multiply(deviceRentalRecordPo.getMonthlyRentalPrice()).divide(totalMonthlyRentalPrice, 5, RoundingMode.HALF_UP);
                    deviceProfitLossDetailPo.setFee(divideFee);
                    ShippingInfoJson exitShippingInfo = deviceRentalRecordPo.getEntryShippingInfo();
                    if (exitShippingInfo != null) {
                        exitShippingInfo.setShippingTotalAmount(divideFee);
                        deviceRentalRecordPo.setEntryShippingInfo(exitShippingInfo);
                    }
                }
            }

            deviceProfitLossDetailPo.setId(identifierGenerator.nextId(deviceProfitLossDetailPo));
            deviceProfitLossDetailPoList_self.add(deviceProfitLossDetailPo);

        }
        deviceProfitLossDetailPoList.addAll(deviceProfitLossDetailPoList_self);
    }

    /**
     * 获取检查设备租赁状态查询Wrapper
     *
     * @return Wrapper
     * @author songkf
     */
    public LambdaQueryWrapper<DeviceRentalRecordPo> getCheckRentalStatusWrapper() {
        List<Long> collect = entryFormInfo.getDeviceInfoList().stream().map(DeviceInfoVo::getDeviceId).collect(Collectors.toList());
        return Wrappers.lambdaQuery(DeviceRentalRecordPo.class)
                .in(DeviceRentalRecordPo::getDeviceId, collect)
                .isNull(DeviceRentalRecordPo::getRentalEndTime);
    }

}
